package recommend;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.ansj.domain.Term;

import segmenter.ChineseSegmenter;
import segmenter.ChineseSegmenterImpl;
import vo.StockInfo;
import vo.UserInterest;

public class RecommenderImpl implements Recommender {
	//修正:
	//本来是对60个content之间计算余弦相似性, 现在是content,title,answer合计180个分别对一个关键词数组计算余弦相似性
	//所以二维数组改为一维数组
	//返回值由二维double数组改为int[]
	/**
	 * 用来计算余弦相似度,返回与给定词语数组余弦相似度最高的10个字符串
	 */
	public int[] calculateMatrix(StockInfo[] stocks,String[] inputKeywords) {
		// 拿到关键词 表
		List<String[]> list;
		list = figureOutKeyWords(stocks);
		List<Int_Dou> IDArray = new ArrayList<Int_Dou>();
		int[] result = new int[10];
		for (int i = 0; i < list.size(); i++) {
				double tempDouble = calculateCosSimiliarity(list.get(i),inputKeywords);
				IDArray.add(new Int_Dou(i, tempDouble));
		}
		Collections.sort(IDArray);
		for(int i=0;i<10;i++) {
			result[i] = IDArray.get(i).newId;
		}
		return result;
	}
	/**
	 * 计算余弦相似度
	 * 
	 * @param s1
	 * @param s2
	 * @return
	 */
	private double calculateCosSimiliarity(String[] s1, String[] s2) {
		// 形成合并无重的关键词表
		List<String> mergeList = new ArrayList<String>();
		for (String temp : s1) {
			mergeList.add(temp);
		}
		for (String temp : s2) {
			if (!mergeList.contains(temp)) {
				mergeList.add(temp);
			}
		}
		// 准备s1和s2各自的词频向量
		int[] s1Vector = new int[mergeList.size()];
		int[] s2Vector = new int[mergeList.size()];
		int cnt = 0;// 用于计数
		int j = 0;

		for (String temp : mergeList) {
			cnt = 0;
			for (int i = 0; i < s1.length; i++) {
				if (temp.equals(s1[i])) {
					cnt++;
				}
			}
			s1Vector[j++] = cnt;
		}

		j = 0;
		for (String temp : mergeList) {
			cnt = 0;
			for (int i = 0; i < s2.length; i++) {
				if (temp.equals(s2[i])) {
					cnt++;
				}
			}
			s2Vector[j++] = cnt;
		}

		// 计算余弦值的分子
		int numerator = 0;
		for (int i = 0; i < s1Vector.length; i++) {
			numerator += s1Vector[i] * s2Vector[i];
		}
		// 计算余弦值的分母
		double denominator = 0;
		double dePart1 = 0;
		double dePart2 = 0;
		for (int i = 0; i < s1Vector.length; i++) {
			dePart1 += s1Vector[i] * s1Vector[i];
		}
		dePart1 = Math.sqrt(dePart1);

		for (int i = 0; i < s2Vector.length; i++) {
			dePart2 += s2Vector[i] * s2Vector[i];
		}
		dePart2 = Math.sqrt(dePart2);
		denominator = dePart1 * dePart2;

		return (numerator / denominator);
	}

	/**
	 * 得到所有content+answer+title的关键词, 以List<String[]>的形式返回
	 * 
	 * @param stocks
	 * @return
	 * 
	 */
	private List<String[]> figureOutKeyWords(StockInfo[] stocks) {
		List<String[]> list = new ArrayList<String[]>();
		List<Term> terms;
		String[] keywords;
		ChineseSegmenter cs = new ChineseSegmenterImpl();
		for (int i = 0; i < stocks.length; i++) {
			// terms是每次循环单条CONTENT的的分词结果
			terms = cs.getWordsFromInput(stocks[i].getCONTENT()+stocks[i].getTITLE()+stocks[i].getANSWER());
			// 开始计算TF-IDF值,由此挑选出20个关键词
			keywords = calculateTF_IDF(terms, stocks);
			list.add(keywords);
		}
		return list;
	}

	/**
	 * 计算单个词的TF值
	 * 
	 * @param term
	 * @param terms
	 * @return
	 */
	private double calculateTF(String term, List<Term> terms) {
		double cnt = 0;// 用来统计term在terms中出现的次数
		for (int i = 0; i < terms.size(); i++) {
			String temp = terms.get(i).getName();
			if (temp.equals(term)) {
				cnt++;
			}
		}
		return (cnt / terms.size());
	}
//适配性修正:
// 将CONTENT和TITLE和ANSWER一起作为语料库
	private double calculateIDF(String term, StockInfo[] stocks) {
		int cnt = 0;// 用于统计term在多少个content/answer/title中出现过
		for (int i = 0; i < stocks.length; i++) {
			if (stocks[i].getCONTENT().indexOf(term)!=-1||stocks[i].getTITLE().indexOf(term)!=-1||stocks[i].getANSWER().indexOf(term)!=-1) {
				cnt++;
			}
		}
		return Math.log((double) stocks.length / (cnt + 1));
	}

	/**
	 * 根据TF_IDF的分布情况计算出单个content的20个关键词
	 * 
	 * @param terms
	 * @param stocks
	 * @return
	 */
	//适应性修改,将private属性改成public属性
	public String[] calculateTF_IDF(List<Term> terms, StockInfo stocks[]) {
		List<SD> SDArray = new ArrayList<SD>();
		double TF = 0;
		double IDF = 0;
		double TF_IDF = 0;
		for (int i = 0; i < terms.size(); i++) {
			TF = calculateTF(terms.get(i).getName(), terms);
			IDF = calculateIDF(terms.get(i).getName(), stocks);
			TF_IDF = TF * IDF;
			SD sd = new SD(terms.get(i).getName(), TF_IDF);
			// add...方法使得当SDArray中没有相同的String时添加当前sd
			addWhenNotDuplicateString(SDArray, sd);
		}

		// 至此已将terms所有的term计算出其TF_IDF值并关联存入SDArray中
		List<String> keywordsArray = new ArrayList<String>();
		// 对SDArray降序排列
		Collections.sort(SDArray);
		for (int k = 0; k < 20 && k < SDArray.size(); k++) {
			keywordsArray.add(SDArray.get(k).word);
		}
		int count = 0;
		String[] keywords = new String[keywordsArray.size()];
		for (String temp : keywordsArray) {
			keywords[count++] = temp;
		}
		return keywords;
	}

	/**
	 * 用于存放单个词和它的TF-IDF值 提供实现Comparable接口,可用Collections.sort()进行排序
	 * 
	 * @author 胡伟
	 */
	private class SD implements Comparable<SD> {
		public SD(String s, double d) {
			tf_idf = d;
			word = s;
		}

		public double tf_idf;
		public String word;

		public int compareTo(SD sd) {
			if ((this.tf_idf - sd.tf_idf) > 0) {
				return -1;
			} else if ((this.tf_idf - sd.tf_idf) < 0) {
				return 1;
			} else {
				return 0;
			}
		}
	}

	/**
	 * 用于存放newsId和它的推荐值(推荐值由协同推荐算法得出) 提供实现Comparable接口,可用Collections.sort()进行排序
	 * 
	 * @author 胡伟
	 *
	 */
	private class Int_Dou implements Comparable<Int_Dou> {
		public int newId;
		public double value;

		public Int_Dou(int i, double d) {
			this.newId = i;
			this.value = d;
		}

		public int compareTo(Int_Dou i_d) {
			if ((this.value - i_d.value) > 0) {
				return -1;
			} else if ((this.value - i_d.value) < 0) {
				return 1;
			} else {
				return 0;
			}
		}
	}

	/**
	 * 不重复String地 向list<SD>中添加元素
	 * 
	 * @param list
	 * @param sd
	 */
	private void addWhenNotDuplicateString(List<SD> list, SD sd) {
		for (SD temp : list) {
			if (temp.word.equals(sd.word)) {
				return;
			}
		}
		list.add(sd);
	}
	@Override
	public double[][] recommend(double[][] matrix, UserInterest[] userInterest) {
		// TODO Auto-generated method stub
		return null;
	}
}